#include "disp_driver.h"
#include <stdint.h>
#include <stdlib.h>
#include <threads.h>

#define MAX_DISP_HOR_RES 320

disp_driver_api api;
configuration config;

void disp_set_backlight(uint8_t level) { gpio_set_level(config.bl_pwm, level); }

void disp_send_cmd(uint8_t cmd) {
    gpio_set_level(config.pin_dc, 0);
    disp_send_data(&cmd, 1);
    gpio_set_level(config.pin_dc, 1);
}

void disp_send_data(void *data, uint16_t length) {
    gpio_set_level(config.pin_cs, 0);
    dirver_spi_send_data(data, length);
    gpio_set_level(config.pin_cs, 1);
}

void disp_driver_init(void) {
    if (strcmp(config.disp_ic, "st7789") == 0) {
        st7789_api_init();
    } else if (strcmp(config.disp_ic, "gc9a01") == 0) {
        gc9a01_api_init();
    } else if (strcmp(config.disp_ic, "st7735") == 0) {
        st7735_api_init();
    } else {
        printf("can find display name  %s\n", config.disp_ic);
        exit(1);
    }

    gpio_init(config.pin_cs);
    gpio_set_direction(config.pin_cs, 0);
    gpio_init(config.pin_dc);
    gpio_set_direction(config.pin_dc, 0);
    gpio_init(config.bl_pwm);
    gpio_set_direction(config.bl_pwm, 0);

    int ret = dirver_spi_init();
    if (ret != 0) {
        perror("SPI dev init fail!\n");
        exit(1);
    }

    // Send all the commands
    uint16_t cmd = 0;
    while (api.disp_init_cmd[cmd].databytes != 0xff) {
        disp_send_cmd(api.disp_init_cmd[cmd].cmd);
        if ((api.disp_init_cmd[cmd].databytes & 0x1F) != 0) {
            disp_send_data(api.disp_init_cmd[cmd].data,
                           api.disp_init_cmd[cmd].databytes & 0x1F);
        }
        if (api.disp_init_cmd[cmd].databytes & 0x80) {
            usleep(api.disp_init_cmd[cmd].delaytime);
        }
        cmd++;
    }
    printf("%s init finish.\n", config.disp_ic);

    disp_set_backlight(1);

    api.disp_set_orientation(config.orientation);
}

void disp_driver_flush(lv_disp_drv_t *drv, const lv_area_t *area,
                       lv_color_t *color_p) {
    // printf("lvgl disp flush\n");
    api.disp_set_window(drv, area);
    uint32_t size = (area->y2 - area->y1) * (area->x2 - area->x1);
    disp_send_data(color_p, size * 2);
}

void lcd_clear(uint16_t color) {
    lv_disp_drv_t drv1;
    const lv_area_t area = {
        .x1 = 0, .x2 = config.height, .y1 = 0, .y2 = config.width};
}